#include <common.h>
#include <asm/armv8/mmu.h>
#include <asm/system.h>
#include <asm/io.h>
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
#include "d2000_common.h"
#include <soc.h>
#include <e_uart.h>
#include "mcu/mcu_info.h"


/******************************************************************/
#ifndef USE_PARAMETER		//当不使用参数表时,在这里设置默认参数
pll_config_t const pll_base_info = {
	.magic = PARAMETER_CPU_MAGIC,
	.version = 0x1,
	.size = 0x30,
	.core_pll = 2200,
	.lmu_pll = 600,
};

common_config_t const common_base_info = {
	.magic = PARAMETER_COMMON_MAGIC,
	.version = 0x1,
	.core_bit_map = 0x3333,
};

peu_config_t const peu_base_info  = {
	.magic = PARAMETER_PCIE_MAGIC,
	.version = 0x1,
	.size = 0x100,
	.independent_tree = CONFIG_INDEPENDENT_TREE,
	.base_cfg = ((CONFIG_PCI_PEU1 | (CONFIG_PEU1_SPLIT_MODE << 1)) << PEU1_OFFSET | \
   				(CONFIG_PCI_PEU0 | (CONFIG_PEU0_SPLIT_MODE << 1))),
   	.ctr_cfg[0].base_config[0] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[0].base_config[1] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[0].base_config[2] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[1].base_config[0] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[1].base_config[1] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[1].base_config[2] = (RC_MODE << PEU_C_OFFSET_MODE) | (GEN3 << PEU_C_OFFSET_SPEED),
	.ctr_cfg[0].equalization[0] = 0x48484848,
	.ctr_cfg[0].equalization[1] = 0x48484848,
	.ctr_cfg[0].equalization[2] = 0x48484848,
	.ctr_cfg[1].equalization[0] = 0x48484848,
	.ctr_cfg[1].equalization[1] = 0x48484848,
	.ctr_cfg[1].equalization[2] = 0x48484848,
};
#endif
static pad_info_t s3_flag_gpio = {
	.pad_sel_reg = 0x28180200,
	.bit_offset = 20,
	.gpio_swport_ddr =GPIO0_BASE + SWPORTA_DDR_OFFSET,
	.gpio_ext_port = GPIO0_BASE + EXT_PORTA_OFFSET,
	.port = 1,
};
//复用gpio0_a1位gpio，且为输入模式（默认为输入模式），读取对应状态


uint32_t gpio_get_s3_flag(void)
{
	p_printf("s3 flag form gpio\n");
	uint32_t temp, temp1, ret;
	
	uint32_t pad_sel_reg = s3_flag_gpio.pad_sel_reg;
	uint32_t bit_offset = s3_flag_gpio.bit_offset;

	uint32_t gpio_swport_ddr = s3_flag_gpio.gpio_swport_ddr;
	uint32_t gpio_ext_port = s3_flag_gpio.gpio_ext_port;
	uint32_t port = s3_flag_gpio.port;

	//读取之前配置方向寄存器
	temp1 = readl((u64)gpio_swport_ddr);
	//配置为输入模式
	writel(temp1 & (1 << port), (u64)gpio_swport_ddr);
	
	temp = readl((u64)pad_sel_reg);
	writel((temp & (~(0xf << bit_offset))) | (0x1 << bit_offset), (u64)pad_sel_reg);
	mdelay(10);
	//读取当前控io寄存器的值
	ret = readl((u64)gpio_ext_port);
	//恢复配置
	writel(temp1, (u64)gpio_swport_ddr);
	writel(temp, (u64)pad_sel_reg);
	
	//判断对应io引脚是否为高电平
	if((1 << port) == ret)
		return	1;
	else
		return	0;	
}


//get reset source 
uint32_t get_reset_source(void)
{
	struct arm_smccc_res res;

	p_printf("get reset source\n");
	arm_smccc_smc(CPU_GET_RST_SOURCE, 0, 0, 0, 0, 0, 0, 0, &res);
	p_printf("reset source = %lx \n", res.a0);
	return res.a0;
}

void pll_init(void)
{
	uint8_t buff[0x100];
	struct arm_smccc_res res;
	//pll init
#ifdef USE_PARAMETER
	pll_config_t pll_base_info;
	get_pm_pll_info(&pll_base_info);	//从参数表中获取参数
#endif
	memcpy(buff, &pll_base_info, sizeof(pll_base_info));
	arm_smccc_smc(CPU_INIT_PLL , 0, (u64)buff, 0, 0, 0, 0, 0, &res);

	if(0 != res.a0){
		p_printf("error ret  %lx\n", res.a0);
		while(1);
	}
}

void pcie_init(void)
{
	uint8_t buff[0x100];
	struct arm_smccc_res res;
	//pcie init
#ifdef USE_PARAMETER
	peu_config_t peu_base_info;
	get_pm_peu_info(&peu_base_info);	//从参数表中获取参数
#endif
	memcpy(buff, &peu_base_info, sizeof(peu_base_info));
	arm_smccc_smc(CPU_INIT_PCIE, 0, (u64)buff, 0, 0, 0, 0, 0, &res);
	if(0 != res.a0){
		p_printf("error ret  %lx\n", res.a0);
		while(1);
	}
}

void ddr_init(uint8_t s3_flag)
{
	uint8_t buff[0x100];
	struct arm_smccc_res res;
#if	1
	mcu_config_t mcu_base_info;

	get_mcu_param_info(&mcu_base_info);
	if(s3_flag)
		mcu_base_info.train_recover = 0x1;		//由参数表中配置和s3_flag决定
	memcpy(buff, &mcu_base_info, sizeof(mcu_base_info));
#endif
	arm_smccc_smc(CPU_INIT_MEM, 0, (u64)buff, 0, 0, 0, 0, 0, &res);
	if(0 != res.a0){
		p_printf("error x0: 0x%lx, x1: 0x%lx\n", res.a0, res.a1);
		uint8_t i;
		for(i=0; i<8; i++){
			if(((res.a1>>24)&0xff) & (1<<i)){
				p_printf("ch %d ", i);
				break;
			}
		}
		switch(res.a1&0xffffff){
			case 0x1:
				p_printf("training fail!\n");
				break;
			default:
				p_printf("error code: 0x%lx\n", res.a1&0xffffff);
				break;
		}
		while(1);
	}
	if(s3_flag){
		//vtt enable
		mdelay(10);
		send_cpld_ctr(6);
		mdelay(40);
		arm_smccc_smc(CPU_INIT_MEM, 3, 0, 0, 0, 0, 0, 0, &res);
	}
}

void sec_init(uint8_t s3_flag)
{
	uint8_t buff[0x100];
	struct arm_smccc_res res;
	uint32_t s3_fun = 0;
	//sec init
#ifdef USE_PARAMETER
	common_config_t common_base_info;
	get_pm_common_info(&common_base_info);	//从参数表中获取参数
#endif
	memcpy(buff, &common_base_info, sizeof(common_base_info));
	if(s3_flag)
		s3_fun = 1;
	arm_smccc_smc(CPU_INIT_SEC_SVC, s3_fun, (u64)buff, 0, 0, 0, 0, 0, &res);
	if(0 != res.a0){
		p_printf("error ret  %lx\n", res.a0);
		while(1);
	}
}

void core_security_level_cfg(void)
{
	//core 安全等级配置
	p_printf("security level cfg...\n");
	struct arm_smccc_res res;
	//level: 0, 1, 2
	uint8_t level_cfg = 0x2;
	arm_smccc_smc(CPU_SECURITY_CFG, 0, level_cfg, 0, 0, 0, 0, 0, &res);
	if(0 != res.a0){
		p_printf("error ret  %lx\n", res.a0);
		while(1);
	}
}

/*只能操作堆栈*/
void check_reset(void)
{
	uint32_t	rst;
	rst = get_reset_source();
	if(0x1 == rst){
		pll_init();
		/*never return*/
	}else if(0x4 == rst){
		return ;	
	}else{
		p_printf("ohter rset source\n");
		while(1);
	}
}

